#include <iostream>
#include "53InheritanceFeatures.hpp"

//  C++中的继承特性

// 在Java中的我们管这个东西叫继承, 但是在C++中继承类叫派生类,被继承的类叫基类

// 现在有这样的一个需求: 一个网球会员,只记录姓名和有没有球桌, 类在53InheritanceFeatures.hpp有定义
// 回顾上面的内容: 下面的两个构造函数等价

// 构造函数1
// TableTennisPlayer::TableTennisPlayer(const string & fn, const string & ln,bool ht)
// {
//     firstname = fn;         // 这里将会先调用string类的复制构造函数,然后调用string的赋值构造函数
//     lastname = ln;
//     hasTable = ht;
// }

// 构造函数2
// TableTennisPlayer::TableTennisPlayer(const string &fn, const string &ln, bool ht) : firstname(fn), lastname(ln), hasTable(ht)
// {
// }
//
// 使用构造函数2可以减少一个步骤,直接使用string的复制构造函数将firstname初始化为fn

//          创建一个继承对象(派生出一个类)      重要!!
// class RatedPlayer : public TableTennisPlayer // 注意这种写法
// {
//     // ......
// };
// 同样定义在53InheritanceFeatures.hpp中
// 冒号指出了 RatedPlayer是 TableTennisPlayer的基类, public指出了TableTennisPlayer是一个公有基类, 这样的派生称为 公有派生.
// 派生类对象包含基类对象派生类对象包含基类对象。使用公有派生，基类的公有成员将成为派生类的公有成员；基类的私有部分也将成为派生类的一部分，但只能通过基类的公有和保护方法访问（稍后
// 将介绍保护成员）。

// 派生类具有以下的特点
//        派生类对象存储了基类的数据成员（派生类继承了基类的实现）；
//        派生类对象可以使用基类的方法（派生类继承了基类的接口）。

// 派生类不能直接访问基类的私有成员，而必须通过基类方法进行访问。
// 例如，RatedPlayer 构造函数不能直接设置继承的成员 (firstname、lastname 和 hasTable), 而必须使用基类的公有方法来访问私有的其类成员。
// 具体地说，派生类构造函数必须使用基类构造函数。 创建派生类对象时， 程序首先创建基类对象。
// 从概念上说，这意味着基类对象应当在程序进入派生类 构造函数之前被创建。C++使用成员初始化列表语法来完成这种工作。例如，下面是第一个RatedPlayer 构造函数的代码：

// 上面告诉了我们一个道理,就是必须在创建派生类之前创建一个基类! 准确的说要使用基类的构造函数!!
// 派生类必须使用基类的构造函数,因为基类的创建必须在派生类之前,所以更多请使用C++成员初始化列表的语法来完成这种工作!!!!!
// 就像下面这样:
RatedPlayer::RatedPlayer(unsigned int r, const string &fn, const string &ln, bool ht) : TableTennisPlayer(fn, ln, ht)       // 调用基类的构造函数,在{}之前
{
    rating = r;
};
// 如果省略了初始化成员列表, 编译器将会使用默认的构造函数的代码进行使用, 也就是说下面的两种方式的代码是等价的
// 代码1
RatedPlayer::RatedPlayer(unsigned int r, const string &fn, const string &ln, bool ht)       // 调用基类的构造函数,在{}之前
{
    rating = r;
};
// 代码2
RatedPlayer::RatedPlayer(unsigned int r, const string &fn, const string &ln, bool ht): TableTennisPlayer()       // 调用基类的构造函数,在{}之前
{
    rating = r;
};

// 下面的构造函数将会使用TableTennisPlayer的复制构造函数,因为ttp是 TableTennisPlayer & 类型,在向TableTennisPlayer类的构造函数传递的过程中将会使用复制构造函数,
// 如果TableTennisPlayer中没有定义复制构造函数,那么编译器将会生成一个默认的复制构造函数,
// 目前来看这样的操作是合适的, 因为TableTennisPlayer没有使用动态内存分配,(对于string,它定义了复制构造函数)
RatedPlayer::RatedPlayer(unsigned int r, const TableTennisPlayer & ttp) : TableTennisPlayer(ttp)       // 在{}之前调用基类的构造函数
{
    rating = r;
};

// 有关派生类构造函数的要点如下：
// 首先创建基类对象；
// 派生类构造函数应通过成员初始化列表将基类信息传递给基类构造函数；派生类构造函数应初始化派生类新增的数据成员。
// 释放对象的顺创建对象的顺反,即首先执行派生类的析构函数，然后自动调用基类的析构函数 !!!!!!

